home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
doskey.arc
/
DOSKEY.ASM
next >
Wrap
Assembly Source File
|
1987-07-01
|
35KB
|
749 lines
;DOSKEY.COM for the IBM Personal Computer - 1987 by Jeff Prosise
;
bios_data segment at 40h ;BIOS Data Area
org 17h ;shift status byte
shft_stat db ?
org 84h
crt_rows db ? ;number of display rows
org 87h
ega_info db ? ;EGA info byte
bios_data ends
;
code segment para public 'code'
assume cs:code
org 100h
begin: jmp initialize
;
copyright db 'Copyright 1987 Ziff-Davis Publishing Co.'
author db 'Jeff Prosise'
;
cls_text db 'CLS',13 ;text of clear screen command
stackptr dw 0 ;primary command stack pointer
locptr dw ? ;secondary command stack pointer
zcount db ? ;stack pointer relative to zero
ega_flag db 0 ;0=no EGA, 1=EGA installed
insert_flag db 0 ;status of insert state
foreground db 7 ;current foreground color
background db 0 ;current background color
dos_segment dw ? ;DOS input buffer segment
columns db ? ;max display column number
bufferptr db ? ;buffer index
;
ftext db 4,'dir ',27 dup (0) ;command linked to F3 key
db 5,'type ',26 dup (0) ;command linked to F4 key
db 5,'copy ',26 dup (0) ;command linked to F5 key
db 4,'del ',27 dup (0) ;command linked to F6 key
db 6,'chdir ',25 dup (0) ;command linked to F7 key
db 5,'path ',26 dup (0) ;command linked to F8 key
db 7,'browse ',24 dup (0) ;command linked to F9 key
db 3,'cls',255,27 dup (0) ;command linked to F10 key
db 7,'backup ',24 dup (0) ;command linked to F11 key
db 8,'restore ',23 dup (0) ;command linked to F12 key
;
dos_int label dword
old21h dw 2 dup (?) ;interrupt 21h vector
old_int_16 dd 0 ; old vector
;
;------------------------------------------------------------------------------
;DOSINT routine intercepts calls to interrupt 21h.
;------------------------------------------------------------------------------
dosint proc near
;
;See if this is a request for DOS function 0Ah.
;
sti ;restore interrupts
cmp ah,0Ah ;function 0Ah?
je dos1 ;yes, then continue
dos_exit: jmp dos_int ;no, then exit to DOS routine
dos1: cmp dos_segment,0 ;has entry occurred before?
jne dos3 ;yes, then branch
;
;Initialize command stack and record DS value if this is the first call.
;
mov dos_segment,ds ;record DOS data segment
push cx ;save CX and SI
push si
mov cx,20 ;initialize command stack area
mov si,offset initialize
dos2: mov byte ptr cs:[si],0
add si,128
loop dos2
pop si ;restore registers
pop cx
;
;See if the function call came from DOS.
;
dos3: push bx ;save BX register
mov bx,ds ;get DS in BX for compare
cmp bx,dos_segment ;call generated from command line?
pop bx ;clean up the stack
jne dos_exit ;no, then exit
;
;Get a command line entry from the standard input device.
;
push ax ;save all registers to be used
push bx
push cx
push dx
push si
push di
push ds
push es
push dx ;resave buffer offset
call input ;read an input string
;
;Copy the entry into the command stack.
;
pop dx ;recover buffer offset
mov si,dx ;point SI to input buffer
mov al,[si+1] ;get length of input string
or al,al ;is the length zero?
je dos6 ;yes, then exit now
inc si ;advance SI to count byte
push cs ;point ES to command stack segment
pop es
mov di,stackptr ;get command stack pointer
mov cl,7 ;convert it to an offset address
shl di,cl
add di,offset initialize
mov cl,al ;transfer string length to CL
inc cl ;increment to include count byte
xor ch,ch ;byte to word in CX
cld ;clear DF
rep movsb ;copy string to command stack
inc stackptr ;update pointer
cmp stackptr,15 ;wrap around if necessary
jne dos4
mov stackptr,0
dos4: mov ax,stackptr ;set LOCPTR = STACKPTR
mov locptr,ax
mov zcount,0 ;initialize base zero pointer
;
;See if the command just entered was CLS.
;
mov si,dx ;point DS:SI to new string
add si,2
mov di,offset cls_text ;and ES:DI to 'CLS' text
mov cx,4 ;four bytes to check
dos5: lodsb ;get one byte
and al,0DFh ;capitalize character
scasb ;do the bytes match?
jne dos6 ;no, then CLS wasn't entered
loop dos5 ;yes, then check another byte
call clear_screen ;clear the screen
sub si,5 ;reset SI to count byte
mov [si],0D00h ;clear string from DOS buffer
;
;Restore registers and exit.
;
dos6: pop es ;restore registers and exit
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
iret
dosint endp
;
;------------------------------------------------------------------------------
;INPUT reads an input string from the standard input device.
;------------------------------------------------------------------------------
input proc near
;
;Record video information and initialize parameters.
;
mov ah,15 ;get video page and columns
int 10h
dec ah ;calculate max column number
mov columns,ah ;save it
push ds ;point ES:DI to buffer
pop es
mov di,dx
add di,2
mov si,dx ;point DS:SI to character count
inc si
mov byte ptr [si],0 ;zero initial count
mov bufferptr,1 ;set initial index value
cld ;clear DF
;
;Wait for a keycode to appear in the keyboard buffer.
;
getkey: mov ah,0Bh ;check keyboard buffer for keycode
int 21h
or al,al ;anything there?
jne getchar ;yes, then go get it
int 28h ;no, then execute interrupt 28h
jmp getkey ;loop back for another try
;
;Read the keycode and process it if it's not an extended code.
;
getchar: mov ah,8 ;read character from buffer
int 21h
or al,al ;is it an extended code?
je excode ;yes, then branch
cmp al,8 ;backspace key?
jne getc1 ;no, then branch
call backspace ;rub out a character
jmp getkey ;return to loop
getc1: cmp al,27 ;ESC key?
jne getc2 ;no, then branch
call clear_line ;yes, then clear input line
mov ax,stackptr ;reset LOCPTR
mov locptr,ax
mov zcount,0 ;reset base zero pointer
jmp getkey
getc2: cmp al,13 ;ENTER key?
je enter ;yes, then branch
call printchar ;no, then print the character
jmp getkey
enter: call eol ;place cursor at end-of-line
mov byte ptr es:[di],13 ;insert carriage return code
mov ah,2 ;advance to next line
mov dl,13
int 21h
ret
;
;Read the extended code and see if one of the keys F3 thru F12 was pressed.
;
excode: mov ah,8 ;get extended code
int 21h
cmp al,133 ;F11?
je fkey
cmp al,134 ;F12?
je fkey
cmp al,61 ;less than F3?
jb ex1 ;yes, then not F3-F10
cmp al,68 ;greater tah 68?
ja ex1 ;yes, then not F3-F10
fkey: test al,80h ;high bit set (F11 or F12)?
jz fkey1 ;no, then branch
sub al,64 ;adjust extended code
fkey1: sub al,61 ;normalize extended code
cbw ;convert byte to word
mov cl,5 ;multiply by 32
shl ax,cl
add ax,offset ftext ;calculate string address
call write_command ;output command
cmp al,255 ;AL 255 on return?
je enter ;yes, then send entry to DOS
jmp getkey ;return to input loop
;
;See if F1 or F2 (or either of the two shifted) was pressed.
;
ex1: cmp al,59 ;F1?
jne ex2
inc foreground ;rotate foreground color forward
cmp foreground,10h ;wrap around if necessary
jne clear
mov foreground,0
jmp clear ;jump to clear screen routine
ex2: cmp al,84 ;Shift-F1?
jne ex3
dec foreground ;decrement foreground color
cmp foreground,0FFh ;wrap around if necessary
jne clear
mov foreground,0Fh
jmp clear
ex3: cmp al,60 ;F2 key?
jne ex4
inc background ;rotate background color forward
cmp background,8 ;wrap around if necesaary
jne clear
mov background,0
jmp clear
ex4: cmp al,85 ;Shift-F2?
jne ex5
dec background ;decrement background color
cmp background,0FFh ;wrap around if necessary
jne clear
mov background,7
clear: call clear_screen ;clear screen and home cursor
mov [si],0D00h ;clear input buffer
ret
;
;See if either Home or End was pressed.
;
ex5: cmp al,71 ;Home?
jne ex6
call home ;home the cursor
mov bufferptr,1 ;reset pointers
mov di,si
inc di
jmp getkey
ex6: cmp al,79 ;End?
jne ex7
call eol ;move cursor to end-of-line
jmp getkey
;
;See if either the left or right-arrow key was pressed.
;
ex7: cmp al,75 ;Cursor-Left?
jne ex8
call move_left ;move left one space
jmp getkey
ex8: cmp al,77 ;Cursor-Right?
jne ex9
call move_right ;move right one space
jmp getkey
;
;See if either INS or DEL was pressed.
;
ex9: cmp al,82 ;INS?
jne ex10
xor insert_flag,1 ;toggle insert flag
jmp getkey
ex10: cmp al,83 ;DEL?
jne ex11
call delete ;delete character at cursor
jmp getkey
;
;Output the last command in the stack if Cursor-Up was pressed.
;
ex11: cmp al,72 ;Up?
jne ex12
cmp zcount,15 ;at upper limit of stack?
je up_exit ;yes, then ignore keypress
mov ax,locptr ;get current stack index
dec ax ;move back one command
cmp ax,0FFFFh ;wrap around if necessary
jne up1
mov ax,14
up1: mov dx,ax ;save AX in DX
mov cl,7 ;calculate address of command
shl ax,cl
add ax,offset initialize
push si ;save SI
mov si,ax ;transfer address to SI
cmp byte ptr cs:[si],0 ;is there a valid command there?
pop si ;restore SI
je up_exit ;no, then ignore keypress
mov locptr,dx ;set LOCPTR
inc zcount ;increment base zero pointer
call write_command ;output the command string
up_exit: jmp getkey
;
;Output the next command in the stack if Cursor-Down was pressed.
;
ex12: cmp al,80 ;Down?
jne ex13
cmp zcount,0 ;at head of command stack?
je ex13 ;yes, then ignore keypress
mov ax,locptr ;get current stack index
inc ax ;advance one command
cmp ax,15 ;wrap around if necessary
jne dn1
xor ax,ax
dn1: mov locptr,ax ;set LOCPTR
dec zcount ;decrement base zero pointer
jnz dn2 ;branch if not at head of stack
call clear_line ;clear command line
jmp getkey ;return to input loop
dn2: mov cl,7 ;calculate address of command
shl ax,cl
add ax,offset initialize
call write_command ;output the command string
ex13: jmp getkey
input endp
;
;------------------------------------------------------------------------------
;PRINT_STRING writes an ASCII string to the command line.
;Entry: DS:SI - string address
; CX - number of characters
;------------------------------------------------------------------------------
print_string proc near
jcxz ps_exit ;exit if no characters
mov ah,2 ;DOS function 2 - output char
ps1: lodsb ;get a byte
mov dl,al ;transfer it to DL
int 21h ;output character
loop ps1 ;loop until done
ps_exit: ret
print_string endp
;
;------------------------------------------------------------------------------
;WRITE_COMMAND outputs a command string.
;Entry: AX - string offset address | Exit: AL - character after string
;------------------------------------------------------------------------------
write_command proc near
push ax ;save address
call clear_line ;clear input line
pop ax ;retrieve string address
push ds ;save DS and SI
push si
push cs ;point DS to string segment
pop ds
mov si,ax ;point SI to the string
mov cl,[si] ;get string length
xor ch,ch
mov byte ptr es:[di-1],cl ;store string length
inc si ;advance SI to string text
write1: mov ah,2 ;print one character
mov dl,[si]
int 21h
movsb ;transfer character to buffer
inc bufferptr ;advance pointer
loop write1 ;loop until done
lodsb ;get first character after string
pop si ;restore registers
pop ds
ret
write_command endp
;
;------------------------------------------------------------------------------
;BACKSPACE deletes the character left of the cursor.
;------------------------------------------------------------------------------
backspace proc near
cmp bufferptr,1 ;at beginning of command line?
je bs_exit ;yes, then ignore it
mov cl,[si] ;get count
sub cl,bufferptr ;calculate distance to end-of-line
inc cl
xor ch,ch
push cx ;save it
jcxz bs1 ;branch if at end-of-line
;
;Shift all characters right of the cursor in the buffer one slot left.
;
push si ;save SI and DI
push di
mov si,di ;position them for shifts
dec di
rep movsb ;shift characters right of cursor
pop di ;restore registers
pop si
;
;Display the new string and update input parameters.
;
bs1: call move_left ;move cursor left
bs2: pop cx ;retrieve shift count
push dx ;save cursor position
push si ;save SI
mov si,di ;point SI to new part of string
call print_string ;print the new part
mov ah,2 ;blank the last character
mov dl,32
int 21h
pop si ;restore registers
pop dx ;restore cursor address
mov ah,2 ;reset the cursor
int 10h
dec byte ptr [si] ;decrement character count
bs_exit: ret
backspace endp
;
;------------------------------------------------------------------------------
;PRINTCHAR writes a new character to the input buffer and echoes it.
;------------------------------------------------------------------------------
printchar proc near
cmp insert_flag,0 ;insert state on?
jne print3 ;yes, then branch
;
;Print a character in overstrike mode.
;
mov cl,[si] ;get count
cmp cl,bufferptr ;end-of-line?
jae print2 ;no, then branch
mov cl,[si-1] ;get maximum length
sub cl,[si] ;subtract current length
cmp cl,1 ;buffer full?
je beep ;yes, then branch
print1: inc byte ptr [si] ;increment count
print2: stosb ;deposit new character
mov ah,2 ;then print it
mov dl,al
int 21h
inc bufferptr ;advance buffer pointer
ret
beep: mov ax,0E07h ;print ASCII 7 thru BIOS
int 10h
ret
;
;Print a character in insert mode.
;
print3: mov cl,[si-1] ;get maximum length
sub cl,[si] ;subtract current count
cmp cl,1 ;buffer full?
je beep ;yes, then branch
mov cl,[si] ;get count
cmp cl,bufferptr ;end-of-line?
jb print1 ;yes, then branch
sub cl,bufferptr ;calculate number of shifts
inc cl
xor ch,ch
push cx ;save shift count
push si ;save SI
add di,cx ;position DI to end-of-line
mov si,di ;position SI just before it
dec si
std ;set DF for now
rep movsb ;make room for new character
cld ;clear DF
pop si ;restore SI
mov es:[di],al ;deposit new character
mov ah,3 ;get cursor position
int 10h
pop cx ;retrieve shift count
inc cx ;increment it
push dx ;save cursor position
push si ;save SI
mov si,di ;point SI to current location
call print_string ;print new part of string
pop si ;restore SI and DX
pop dx
mov ah,2 ;reset cursor position
int 10h
inc byte ptr [si] ;add to character count
jmp move_right ;move cursor right
printchar endp
;
;------------------------------------------------------------------------------
;DELETE deletes the character at the cursor.
;------------------------------------------------------------------------------
delete proc near
mov cl,[si] ;get count
cmp cl,bufferptr ;end-of-line?
jb del2 ;yes, then ignore keypress
sub cl,bufferptr ;calculate number of shifts
xor ch,ch ;byte to word in CX
push cx ;save shift count
jcxz del1 ;branch if no shifts
push si ;save SI and DI
push di
mov si,di ;position registers for shift
inc si
rep movsb ;shift characters right of cursor
pop di ;restore registers
pop si
del1: mov ah,3 ;get cursor position
int 10h
jmp bs2 ;exit through BACKSPACE routine
del2: ret
delete endp
;
;------------------------------------------------------------------------------
;MOVE_LEFT moves the cursor one character left.
;------------------------------------------------------------------------------
move_left proc near
cmp bufferptr,1 ;at beginning of line?
je left3 ;yes, then ignore keypress
mov ah,3 ;get cursor position
int 10h
or dl,dl ;column 0?
je left1 ;yes, then branch
dec dl ;decrement column number
jmp left2
left1: mov dl,columns ;position at end of previous line
dec dh
left2: mov ah,2 ;set new position
int 10h
dec di ;decrement pointers
dec bufferptr
left3: ret
move_left endp
;
;------------------------------------------------------------------------------
;MOVE_RIGHT moves the cursor one character right.
;------------------------------------------------------------------------------
move_right proc near
mov cl,[si] ;get count
cmp cl,bufferptr ;end-of-line?
jb rt3 ;yes, then ignore keypress
mov ah,3 ;get cursor position
int 10h
cmp dl,columns ;at end-of-line?
je rt1 ;yes, then branch
inc dl ;increment column number
jmp rt2
rt1: xor dl,dl ;beginning of next line
inc dh
rt2: mov ah,2 ;position cursor
int 10h
inc di ;advance pointers
inc bufferptr
rt3: ret
move_right endp
;
;------------------------------------------------------------------------------
;HOME relocates the cursor to the beginning of the command line.
;------------------------------------------------------------------------------
home proc near
mov cl,bufferptr ;get position pointer
dec cl ;calculate distance from start
xor ch,ch
jcxz home_exit ;exit if already there
home1: push cx ;save count
call move_left ;move left one space
pop cx ;retrieve count
loop home1 ;loop until done
home_exit: ret
home endp
;
;------------------------------------------------------------------------------
;EOL advances the cursor to the end of the command line.
;------------------------------------------------------------------------------
eol proc near
mov cl,[si] ;get count
cmp cl,bufferptr ;already at end?
jb eol_exit ;yes, then exit
sub cl,bufferptr ;calculate distance from end
inc cl
xor ch,ch ;byte to word in CX
eol1: push cx ;advance right CX times
call move_right
pop cx
loop eol1
eol_exit: ret
eol endp
;
;------------------------------------------------------------------------------
;CLEAR_LINE clears the command line.
;------------------------------------------------------------------------------
clear_line proc near
mov cl,[si] ;get count
xor ch,ch
jcxz cline2 ;exit if no characters
push cx ;save count
call home ;home the cursor
mov ah,3 ;get cursor position
int 10h
pop cx ;restore CX
push dx ;save cursor address
mov ah,2 ;print ASCII spaces
mov dl,32
cline1: int 21h
loop cline1
mov ah,2 ;home cursor again
pop dx
int 10h
mov byte ptr [si],0 ;reset parameters
mov bufferptr,1
mov di,si
inc di
cline2: ret
clear_line endp
;------------------------------------------------------------------------------
;CLEAR_SCREEN clears the display to the currently selected colors.
;------------------------------------------------------------------------------
clear_screen proc near
push ds ;save DS
mov ax,bios_data ;point DS to BIOS Data Area
mov ds,ax
assume ds:bios_data
mov dl,columns ;set number of columns
mov dh,25 ;set number of screen rows
cmp ega_flag,0 ;is there an EGA installed?
je clear1 ;no, then branch
test ega_info,8 ;is the EGA the active monitor?
jnz clear1 ;no, then branch
mov dh,crt_rows ;get number of screen rows
clear1: mov bh,background ;formulate attribute for clear
mov cl,4
shl bh,cl
or bh,foreground
mov ax,0600h ;video function - scroll screen
xor cx,cx ;designate entire screen
int 10h ;clear the display
mov ah,15 ;determine active video page
int 10h
mov ah,2 ;home the cursor
xor dx,dx
int 10h
pop ds ;restore DS
assume ds:nothing
ret
clear_screen endp
;
;----------------------------------------------------------------------
;This enhancement for Int 16 is installed only on machines that use it.
;----------------------------------------------------------------------
int_16 proc far
assume cs:code, ds:nothing, es:nothing, ss:nothing
pushf ;save the flags
sti ;allow interrupts
cmp ah,2 ;affects only fn 0,1
jb bios_1
bios_0:
popf ;restore flags
jmp old_int_16 ;continue on
bios_1:
or ah,10h ;make extended fn
call old_int_16 ;call old handler
pushf ;save flags
cmp al,0e0h ;If low byte isn't E0
jne bios_2 ; continue normally
or ah,ah ;If char(224)
jz bios_2 ; continue
xor al,al ;else make normal extended
bios_2:
popf ;restore these flags
ret 2 ;discard original ones
int_16 endp
;------------------------------------------------------------------------------
;INITIALIZE leaves DOSKEY resident in memory.
;------------------------------------------------------------------------------
initialize proc near
assume ds:code
;
;Determine whether an EGA is installed.
;
mov ah,12h ;BIOS video function 12h
mov bl,10h ;return EGA info subfunction
int 10h ;get info
cmp bl,10h ;did BL return unchanged?
je init1 ;yes, then there's no EGA here
inc ega_flag ;no, then there is an EGA
;
;Save and replace interrupt vectors.
;
init1:
mov ax,3521h ;save and replace int 21h vector
int 21h
mov old21h,bx
mov old21h[2],es
mov ah,25h
lea dx,dosint
int 21h
;
; Determine if BIOS supports enhanced keys.
;
xor ax,ax
mov es,ax
assume es:nothing
xor byte ptr es:[417h],80h
mov ah,12h
int 16h
cmp al,byte ptr es:[417h]
jne no_support
xor byte ptr es:[417h],80h
mov ah,12h
int 16h
cmp al,byte ptr es:[417h]
jne no_support
mov ax,3516h
int 21h
mov word ptr old_int_16,bx
mov word ptr old_int_16[2],es
mov ah,25h
mov dx,offset int_16
int 21h
no_support:
;
;Terminate but leave interrupt handling code and buffer space resident.
;
mov dx,offset initialize+1920 ;point DX to end of reserved area
int 27h ;terminate-but-stay-resident
initialize endp
;
code ends
end begin